package ie.flax.flaxengine.client; import java.util.Date; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import com.google.gwt.logging.client.HasWidgetsLogHandler; import com.google.gwt.logging.client.HtmlLogFormatter; import com.google.gwt.logging.client.SystemLogHandler; import com.google.gwt.logging.client.TextLogFormatter; import com.google.gwt.logging.impl.FormatterImpl; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.ScrollPanel; /** * Use this for logging. FLog outputs to a scrollable panel, which is accessed * by getWidget(). FLog also logs to the Webkit and Firebug, and IE9 consoles. * It formats things fairly nicely also. You need to call init() before using * this - if you don't call, FLog will fail silently, which is useful-ish for * production stuff. If you don't want end-users reading your logs, don't call * init(). Not calling init() will also probably make your code (a really tiny * bit) smaller, thanks to GWT's compiler. * * @author carllange * */ public class FLog { private static final Logger l = Logger.getLogger("FLog"); private static HorizontalPanel topPanel = new HorizontalPanel(); private static ScrollPanel scrollPanel = new ScrollPanel(); private static HTMLPanel logWidget = new HTMLPanel(""); private static boolean inited = false; /** * Logs a debug message. * * @param string * Log message */ public static void debug(String string) { if (inited) { scrollPanel.scrollToBottom(); l.log(new LogRecord(Level.FINE, string)); } } /** * Logs an error message. * * @param string * Log message */ public static void error(String string) { if (inited) { scrollPanel.scrollToBottom(); l.log(new LogRecord(Level.SEVERE, string)); } } /** * You don't need to use this, but if you don't want to use the browser's * console, it's a nice alternative. You can put this panel anywhere that * can take panels. * * @return {@link HorizontalPanel} The log panel. */ public static HorizontalPanel getWidget() { return topPanel; } /** * Logs an info message. * * @param string * Log message */ public static void info(String string) { if (inited) { l.log(new LogRecord(Level.INFO, string)); } } /** * Initialises the logger. Do not call this if you don't want to log things, * as everything else should fail silently. If this is not called, it should * also make your code size smaller (by a tiny bit), by not compiling other * stuff in this class. */ public static void init() { if (!inited) { l.setUseParentHandlers(false); l.addHandler(new SystemLogHandler()); FLogConsoleLogHandler clh = new FLogConsoleLogHandler(); clh.setFormatter(new FLogConsoleFormatter()); HasWidgetsLogHandler hwlh = new HasWidgetsLogHandler(logWidget); hwlh.setFormatter(new FLogHtmlFormatter()); l.addHandler(clh); l.addHandler(hwlh); scrollPanel.setHeight("140px"); scrollPanel.add(logWidget); topPanel.add(scrollPanel); inited = true; } } /** * Logs a trace message. * * @param string * Log message */ public static void trace(String string) { if (inited) { l.log(new LogRecord(Level.FINEST, string)); } } /** * Logs a warning message. * * @param string * Log message */ public static void warn(String string) { if (inited) { scrollPanel.scrollToBottom(); l.log(new LogRecord(Level.WARNING, string)); } } } /** * The html formatter for FLog. This formats {@link LogRecord} objects into * pretty html. You shouldn't use or modify this if you don't know what you're * doing. * * @author carllange * */ class FLogHtmlFormatter extends HtmlLogFormatter { private static String newline = "__GWT_LOG_FORMATTER_BR__"; public FLogHtmlFormatter() { super(false); } @Override public String format(LogRecord event) { StringBuilder html = new StringBuilder(getHtmlPrefix(event)); html.append(getHtmlPrefix(event)); html.append(getRecordInfo(event, " ")); html.append(getEscaped(event.getMessage())); html.append(getHtmlSuffix(event)); return html.toString(); } private String getColor(int logLevel) { if (logLevel == Level.OFF.intValue()) return "#000"; // black else if (logLevel >= Level.SEVERE.intValue()) return "#F00"; // bright red else if (logLevel >= Level.WARNING.intValue()) return "#E56717"; // orange else if (logLevel >= Level.INFO.intValue()) return "#20b000"; // green else if (logLevel >= Level.CONFIG.intValue()) return "#2B60DE"; // blue else if (logLevel >= Level.FINE.intValue()) return "#F0F"; // purple else if (logLevel >= Level.FINER.intValue()) return "#F0F"; // purple else if (logLevel >= Level.FINEST.intValue()) return "#F0F"; // purple return "#000"; // black } private String getEscaped(String text) { text = text.replaceAll("<", "<"); text = text.replaceAll(">", ">"); text = text.replaceAll(newline, "<br>"); return text; } private String getName(String name) { String r = ""; if (name.equalsIgnoreCase("finest")) { r = "TRACE"; } else if (name.equalsIgnoreCase("finer")) { r = "TRACE"; } else if (name.equalsIgnoreCase("fine")) { r = "TRACE"; } else if (name.equalsIgnoreCase("config")) { r = "DEBUG"; } else if (name.equalsIgnoreCase("info")) { r = "INFO"; } else if (name.equalsIgnoreCase("warning")) { r = "WARN"; } else if (name.equalsIgnoreCase("severe")) { r = "ERROR"; } return r; } @Override protected String getHtmlPrefix(LogRecord event) { StringBuilder prefix = new StringBuilder(); prefix.append("<span style='color:"); prefix.append(getColor(event.getLevel().intValue())); prefix.append("'>"); prefix.append("<code>"); return prefix.toString(); } @Override protected String getRecordInfo(LogRecord event, String newline) { Date date = new Date(event.getMillis()); String time = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds(); StringBuilder s = new StringBuilder(); s.append(time); s.append(" "); s.append(newline); s.append(getName(event.getLevel().getName())); s.append(": "); return s.toString(); } } class FLogConsoleLogHandler extends Handler { public FLogConsoleLogHandler() { setFormatter(new TextLogFormatter(true)); setLevel(Level.ALL); } @Override public void close() { // No action needed } @Override public void flush() { // No action needed } @Override public void publish(LogRecord record) { if (!isSupported() || !isLoggable(record)) { return; } String msg = getFormatter().format(record); String n = getName(record.getLevel().getName()); if ((n == "TRACE") || (n == "DEBUG") || (n == "INFO")) { nlDebug(msg); } else if (n == "WARN") { nlWarn(msg); } else if (n == "ERROR") { nlErr(msg); } else { log(msg); } } private String getName(String name) { String r = ""; if (name.equalsIgnoreCase("finest")) { r = "TRACE"; } else if (name.equalsIgnoreCase("finer")) { r = "TRACE"; } else if (name.equalsIgnoreCase("fine")) { r = "TRACE"; } else if (name.equalsIgnoreCase("config")) { r = "DEBUG"; } else if (name.equalsIgnoreCase("info")) { r = "INFO"; } else if (name.equalsIgnoreCase("warning")) { r = "WARN"; } else if (name.equalsIgnoreCase("severe")) { r = "ERROR"; } return r; } private native boolean isSupported() /*-{ return ((window.console != null) && (window.console.firebug == null) && (window.console.log != null) && (typeof (window.console.log) == 'function')); }-*/; private native void log(String message) /*-{ window.console.log(message); }-*/; private native void nlDebug(String message) /*-{ window.console.debug(message); }-*/; private native void nlWarn(String message) /*-{ window.console.warn(message); }-*/; private native void nlErr(String message) /*-{ window.console.error(message); }-*/; } /** * The console formatter for FLog. This formats {@link LogRecord} objects so * that they look nice in the Webkit, Firebug, and possibly IE9 consoles. You * shouldn't use or modify this if you don't know what you're doing. * * @author carllange * */ class FLogConsoleFormatter extends FormatterImpl { @Override public String format(LogRecord event) { StringBuilder html = new StringBuilder(); html.append(getRecordInfo(event, " ")); html.append(event.getMessage()); return html.toString(); } private String getName(String name) { String r = ""; if (name.equalsIgnoreCase("finest")) { r = "TRACE"; } else if (name.equalsIgnoreCase("finer")) { r = "TRACE"; } else if (name.equalsIgnoreCase("fine")) { r = "TRACE"; } else if (name.equalsIgnoreCase("config")) { r = "DEBUG"; } else if (name.equalsIgnoreCase("info")) { r = "INFO"; } else if (name.equalsIgnoreCase("warning")) { r = "WARN"; } else if (name.equalsIgnoreCase("severe")) { r = "ERROR"; } return r; } @Override protected String getRecordInfo(LogRecord event, String newline) { Date date = new Date(event.getMillis()); String time = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds(); StringBuilder s = new StringBuilder(); s.append(time); s.append(" "); s.append(newline); s.append(getName(event.getLevel().getName())); s.append(": "); return s.toString(); } }